package com.hgyc.mom.common.redis;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * spring redis 工具类
 *
 * @author fwj
 **/
@SuppressWarnings(value = { "unchecked", "rawtypes" })
@Slf4j
@Component
public class RedisCache
{
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private ObjectMapper objectMapper;

    public <T> void setCacheObject(final String key, final T value) {
        try {
            String toStore;
            if (value instanceof String) {
                toStore = (String) value;
            } else {
                toStore = objectMapper.writeValueAsString(value);
            }
            stringRedisTemplate.opsForValue().set(key, toStore);
        } catch (Exception e) {
            log.error("Redis 存储序列化失败 key={} 错误={}", key, e.getMessage(), e);
        }
    }

    public <T> void setCacheObject(final String key, final T value, long timeout, TimeUnit unit) {
        try {
            String toStore;
            if (value instanceof String) {
                toStore = (String) value;
            } else {
                toStore = objectMapper.writeValueAsString(value);
            }
            stringRedisTemplate.opsForValue().set(key, toStore, timeout, unit);
        } catch (Exception e) {
            log.error("Redis 存储序列化失败 key={} 错误={}", key, e.getMessage());
        }
    }

    public <T> T getCacheObject(final String key, Class<T> clazz) {
        String json = stringRedisTemplate.opsForValue().get(key);
        if (json == null) return null;
        try {
            return objectMapper.readValue(json, clazz);
        } catch (Exception e) {
            log.error("Redis 反序列化失败 key={} 数据={} 错误={}", key, json, e.getMessage());
            return null;
        }
    }

    public boolean expire(final String key, final long timeout, final TimeUnit unit) {
        return Boolean.TRUE.equals(stringRedisTemplate.expire(key, timeout, unit));
    }

    public long getExpire(final String key) {
        return stringRedisTemplate.getExpire(key);
    }

    public boolean hasKey(final String key) {
        return Boolean.TRUE.equals(stringRedisTemplate.hasKey(key));
    }

    public boolean deleteObject(final String key) {
        return Boolean.TRUE.equals(stringRedisTemplate.delete(key));
    }

    public boolean deleteObject(final Collection<String> keys) {
        return stringRedisTemplate.delete(keys) > 0;
    }

    public <T> long setCacheList(final String key, final List<T> dataList) {
        try {
            List<String> jsonList = dataList.stream()
                    .map(obj -> {
                        try {
                            return objectMapper.writeValueAsString(obj);
                        } catch (Exception e) {
                            log.warn("序列化失败：{}", e.getMessage());
                            return null;
                        }
                    })
                    .filter(Objects::nonNull)
                    .collect(Collectors.toList());
            return stringRedisTemplate.opsForList().rightPushAll(key, jsonList);
        } catch (Exception e) {
            log.error("缓存 List 失败 key={} 错误={}", key, e.getMessage());
            return 0;
        }
    }

    public <T> List<T> getCacheList(final String key, Class<T> clazz) {
        try {
            List<String> jsonList = stringRedisTemplate.opsForList().range(key, 0, -1);
            if (jsonList == null || jsonList.isEmpty()) {
                return Collections.emptyList();
            }
            List<T> result = new ArrayList<>();
            for (String json : jsonList) {
                try {
                    result.add(objectMapper.readValue(json, clazz));
                } catch (Exception e) {
                    log.warn("反序列化失败：{}", e.getMessage());
                }
            }
            return result;
        } catch (Exception e) {
            log.error("缓存 List 获取失败 key={} 错误={}", key, e.getMessage());
            return Collections.emptyList();
        }
    }

    public <T> long setCacheSet(final String key, final Set<T> dataSet) {
        try {
            Set<String> jsonSet = dataSet.stream()
                    .map(obj -> {
                        if (obj instanceof String) {
                            return (String) obj;
                        }
                        try {
                            return objectMapper.writeValueAsString(obj);
                        } catch (Exception e) {
                            log.warn("序列化失败：{}", e.getMessage());
                            return null;
                        }
                    })
                    .filter(Objects::nonNull)
                    .collect(Collectors.toSet());

            return stringRedisTemplate.opsForSet().add(key, jsonSet.toArray(new String[0]));
        } catch (Exception e) {
            log.error("缓存 Set 失败 key={} 错误={}", key, e.getMessage());
            return 0;
        }
    }

    public <T> Set<T> getCacheSet(final String key, Class<T> clazz) {
        try {
            Set<String> jsonSet = stringRedisTemplate.opsForSet().members(key);
            if (jsonSet == null || jsonSet.isEmpty()) {
                return Collections.emptySet();
            }
            Set<T> result = new HashSet<>();
            for (String json : jsonSet) {
                try {
                    result.add(objectMapper.readValue(json, clazz));
                } catch (Exception e) {
                    log.warn("反序列化失败：{}", e.getMessage());
                }
            }
            return result;
        } catch (Exception e) {
            log.error("缓存 Set 获取失败 key={} 错误={}", key, e.getMessage());
            return Collections.emptySet();
        }
    }

    public <T> void setCacheMap(final String key, final Map<String, T> dataMap) {
        try {
            Map<String, String> jsonMap = new HashMap<>();
            for (Map.Entry<String, T> entry : dataMap.entrySet()) {
                String json;
                if (entry.getValue() instanceof String) {
                    json = (String) entry.getValue();
                } else {
                    json = objectMapper.writeValueAsString(entry.getValue());
                }
                jsonMap.put(entry.getKey(), json);
            }
            stringRedisTemplate.opsForHash().putAll(key, jsonMap);
        } catch (Exception e) {
            log.error("缓存 Map 失败 key={} 错误={}", key, e.getMessage());
        }
    }

    public <T> Map<String, T> getCacheMap(final String key, Class<T> clazz) {
        try {
            Map<Object, Object> entries = stringRedisTemplate.opsForHash().entries(key);
            Map<String, T> resultMap = new HashMap<>();
            for (Map.Entry<Object, Object> entry : entries.entrySet()) {
                try {
                    String mapKey = (String) entry.getKey();
                    String json = (String) entry.getValue();
                    resultMap.put(mapKey, objectMapper.readValue(json, clazz));
                } catch (Exception e) {
                    log.warn("反序列化 Map 失败：{}", e.getMessage());
                }
            }
            return resultMap;
        } catch (Exception e) {
            log.error("缓存 Map 获取失败 key={} 错误={}", key, e.getMessage());
            return Collections.emptyMap();
        }
    }

    public <T> void setCacheMapValue(final String key, final String hKey, final T value) {
        try {
            String jsonValue;
            if (value instanceof String) {
                jsonValue = (String) value;
            } else {
                jsonValue = objectMapper.writeValueAsString(value);
            }
            stringRedisTemplate.opsForHash().put(key, hKey, jsonValue);
        } catch (Exception e) {
            log.error("缓存 Hash 单条失败 key={} field={} 错误={}", key, hKey, e.getMessage());
        }
    }

    public <T> T getCacheMapValue(final String key, final String hKey, Class<T> clazz) {
        Object json = stringRedisTemplate.opsForHash().get(key, hKey);
        if (json == null) return null;
        try {
            if (clazz == String.class) {
                return clazz.cast(json);
            }
            return objectMapper.readValue(String.valueOf(json), clazz);
        } catch (Exception e) {
            log.warn("反序列化 Hash 单条失败 key={} field={} 错误={}", key, hKey, e.getMessage());
            return null;
        }
    }

    public boolean deleteCacheMapValue(final String key, final String hKey) {
        return stringRedisTemplate.opsForHash().delete(key, hKey) > 0;
    }

    public Set<String> keys(final String pattern) {
        return stringRedisTemplate.keys(pattern);
    }

    /**
     * 批量获取 JSON 存储的 Map<String, String>
     */
    public Map<String, Map<String, String>> batchGetDictMaps(List<String> keys) {
        List<String> jsonList = stringRedisTemplate.opsForValue().multiGet(keys);
        Map<String, Map<String, String>> result = new LinkedHashMap<>();
        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            String json = jsonList != null ? jsonList.get(i) : null;
            if (json != null) {
                try {
                    Map<String, String> map = objectMapper.readValue(json, new TypeReference<Map<String, String>>() {});
                    result.put(key, map);
                } catch (Exception e) {
                    log.warn("批量反序列化失败 key={} 错误={}", key, e.getMessage());
                }
            }
        }
        return result;
    }

    private void processEntry(String key, Object value, Map<String, Map<String, String>> result) {
        ObjectMapper objectMapper = null;
        try {
            if (value != null) {
                Map<String, String> map = objectMapper.convertValue(
                        value,
                        new TypeReference<>() {}
                );
                result.put(key,  map);
            }
        } catch (IllegalArgumentException e) {
            log.warn("Redis 值转换失败 key={}", key, e);
        }
    }

    private Map<String, Map<String, String>> handlePartialResults(
            List<String> keys,
            List<Object> values
    ) {
        Map<String, Map<String, String>> result = new HashMap<>();
        if (values == null) {
            return result;
        }

        for (int i = 0; i < Math.min(keys.size(),  values.size());  i++) {
            if (values.get(i)  != null) {
                processEntry(keys.get(i),  values.get(i),  result);
            }
        }
        return result;
    }

    public String getString(String key) {
        return stringRedisTemplate.opsForValue().get(key);
    }
}
